package yxy.game.pm2.bean.module;

import org.redisson.api.RLock;
import yxy.apple.logger.Logger;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.cherry.game.base.redis.RedisType;

import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;

/**
 * <pre>
 *      封装redisson分布式锁
 * <pre/>
 * @ClassName RedissonLock
 * @Author jingtao-zheng
 * @Date 2022/7/16 21:52
 * @Version 1.0
 **/
public class RedissonLock {
    protected static Logger logger = Logger.create(RedissonLock.class);
    /**
     * <pre>
     *   默认tryLock锁
     *   锁最长等待时间10秒，10秒还不获得锁就直接放行
     *   最多持有锁10秒，占有锁超过10秒就自动释放锁
     *   警告：
     *   1.如果业务处理时长超过10秒请不要使用该锁
     *   2.不同库的Redisson为单例，
     *   所以不要在同一线程多次加锁时，使用同样的key
     *     如果有疑问请自行看源码
     *     {@link yxy.cherry.game.Game#initRedis(yxy.cherry.game.Configuration)}
     *     {@link org.redisson.RedissonLock#RedissonLock(org.redisson.command.CommandAsyncExecutor, String)}
     * <pre/>
     *
     * @param business 需要加锁的业务代码
     * @param key      锁名称
     * @Author jingtao-zheng
     */
    public static boolean tryLock(BooleanSupplier business, String key) {
        RLock lock = getRLock(key);
        try {        //尝试加锁
            if (lock.tryLock(10, 10, TimeUnit.SECONDS)) {
                //logger.info("线程：%s拿到锁#################时间:%s", Thread.currentThread().getName(), DateTime.now().getMillis());
                try {
                    //加锁成功执行业务
                    return business.getAsBoolean();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    //业务结束会自动释放锁,放if里面也是防止没加锁就解锁的报错
                    //logger.info("线程：%s解锁锁#################时间:%s", Thread.currentThread().getName(), DateTime.now().getMillis());
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static RLock getRLock(String key) {
        try {
            return RedisManager.client(RedisManager.getInstance().getConnection(RedisType.REDIS_GAME)).getLock(key);
        } catch (RedisException e) {
            e.printStackTrace();
        }
        return null;
    }

}
